import { defineEventHandler, setResponseHeader, getRequestURL } from 'h3'; import { createPageHandler } from '@beatzball/litro/runtime/create-page-handler.js'; import type { LitroRoute } from '@beatzball/litro'; import { routes, pageModules } from '#litro/page-manifest'; function matchRoute( pathname: string, ): { route: LitroRoute; params: Record } | undefined { for (const route of routes) { if (route.isCatchAll) return { route, params: {} }; if (!route.isDynamic) { if (pathname === route.path) return { route, params: {} }; continue; } // Use named capture groups so param values are automatically mapped to names. const regexStr = '^' + route.path .replace(/:([^/]+)\(\.\*\)\*/g, '(?<$1>.+)') .replace(/:([^/?]+)\?/g, '(?<$1>[^/]*)?') .replace(/:([^/]+)/g, '(?<$1>[^/]+)') + '$'; try { const match = pathname.match(new RegExp(regexStr)); if (match) return { route, params: (match.groups ?? {}) as Record }; } catch { // malformed pattern — skip } } return undefined; } export default defineEventHandler(async (event) => { const pathname = getRequestURL(event).pathname; const result = matchRoute(pathname); if (!result) { setResponseHeader(event, 'content-type', 'text/html; charset=utf-8'); return ` 404

404 — Not Found

No page matched ${pathname}.

`; } const { route: matched, params } = result; // Populate route params (e.g. slug from /blog/:slug) on the event context // so pageData fetchers can access them via event.context.params. event.context.params = { ...event.context.params, ...params }; const handler = createPageHandler({ route: matched, pageModule: pageModules[matched.filePath], }); return handler(event); });